;;; GNU Guix --- Functional package management for GNU
;;;
;;; Copyright © 2022 (unmatched parenthesis <paren@disroot.org>
;;; Copyright © 2022 jgart <jgart@dismail.de>
;;;
;;; This file is not part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (guixrus packages common python)
  #:use-module (guix build-system copy)
  #:use-module (guix build-system python)
  #:use-module (guix download)
  #:use-module (guix git-download)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix packages)
  #:use-module (gnu packages check)
  #:use-module (gnu packages compression)
  #:use-module (gnu packages databases)
  #:use-module (gnu packages libusb)
  #:use-module (gnu packages python)
  #:use-module (gnu packages python-check)
  #:use-module (gnu packages python-crypto)
  #:use-module (gnu packages python-web)
  #:use-module (gnu packages python-xyz)
  #:use-module (gnu packages security-token)
  #:use-module (gnu packages time)
  #:use-module (gnu packages xorg)
  #:use-module ((guixrus licenses) #:prefix license:))

(define-public python-pyinjector
  (package
    (name "python-pyinjector")
    (version "1.0.6")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "pyinjector" version ".zip"))
        (sha256
          (base32 "126n70qmrlqd25xmxwaf800abfm1k250zx01kx3dha2p6pk3vx89"))))
    (build-system python-build-system)
    (native-inputs (list unzip))
    (home-page "https://github.com/kmaork/pyinjector")
    (synopsis
      "Tool/library allowing dynamic library injection into running processes")
    (description
      "This package provides a tool and library for dynamic library injection into
running processes.")
    (license license:expat)))

(define-public python-hypno
  (package
    (name "python-hypno")
    (version "0.1.4")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "hypno" version ".zip"))
        (sha256
          (base32 "1703c1k1g404sl2yvh5wylk7prnfgm7c83cpx2gv3n50025d6910"))))
    (build-system python-build-system)
    (propagated-inputs (list python-pyinjector))
    (native-inputs (list unzip))
    (home-page "https://github.com/kmaork/hypno")
    (synopsis
      "Tool/library for injecting python code into a running python process")
    (description
      "This package provides a tool and library that can inject python code into
a running python process.")
    (license license:expat)))

(define-public python-madbg
  (package
    (name "python-madbg")
    (version "1.2.0")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "madbg" version ".zip"))
        (sha256
          (base32 "19cll917w3zshxrcf2v5bdwkvbam3nslyik2hp4wpn5z4xkzsw5v"))))
    (build-system python-build-system)
    (propagated-inputs
      (list python-click python-hypno python-ipython python-prompt-toolkit))
    (native-inputs (list unzip))
    (home-page "https://github.com/kmaork/madbg")
    (synopsis "Fully-featured remote debugger for python")
    (description
      "This package provides a fully-featured remote debugger for python.")
    (license license:expat)))

(define-public python-pynvim
  (package
    (name "python-pynvim")
    (version "0.4.3")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "pynvim" version))
        (sha256
          (base32 "1zvdspp6gm3gbh7dpwa2amld44y6x6dsk8dkpqphks75pmw56y9s"))))
    (build-system python-build-system)
    ;; tries to make a HTTPS connection?
    (arguments (list #:tests? #f))
    (propagated-inputs (list python-greenlet python-msgpack))
    (home-page "http://github.com/neovim/pynvim")
    (synopsis "Write Neovim plugins in Python")
    (description "This package provides a library for writing Neovim plugins in Python.")
    (license license:asl2.0)))

(define-public python-yes-no-words
  (package
    (name "python-yes-no-words")
    (version "2022.4.4")
    (source
     (origin
       (method git-fetch)
       (uri
        (git-reference
        ;; PyPi does not include the test file.
         (url "https://github.com/jefftriplett/yes-no-words")
         (commit version)))
       (file-name (git-file-name name version))
       (sha256
        (base32 "04xnackm2xqgahlbw9iw4y6d0bbb5p7cnvqjvabncrpm9w3jmm8q"))))
    (build-system python-build-system)
    (native-inputs (list python-pytest))
    (arguments
      '(#:phases
        (modify-phases %standard-phases
          (replace 'check
            (lambda* (#:key tests? inputs outputs #:allow-other-keys)
              (when tests?
                (invoke "pytest" "-v" "test_yes_no_words.py")))))))
    (home-page "https://github.com/jefftriplett/yes-no-words/")
    (synopsis "Get yes/no-like words")
    (description "Get yes/no-like words.")
    (license license:asl2.0)))

(define-public python-supervisor
  (package
    (name "python-supervisor")
    (version "4.2.4")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "supervisor" version))
        (sha256
          (base32 "18lpddhyl8ziy6lc0klassxpd8kdg8c0nhkrvz1k3ipfw4n5ip20"))))
    (build-system python-build-system)
    (native-inputs
      (list python-pytest python-pytest-cov))
    (arguments (list #:tests? #f)) ; fixme
    (home-page "http://supervisord.org/")
    (synopsis "A system for controlling process state under UNIX")
    (description
      "This package provides a system for controlling process state under UNIX")
    (license
      ;; https://github.com/Supervisor/supervisor/issues/1364
      (license:fsf-free (string-append "https://web.archive.org/web/20190211105114/"
                                       "http://www.repoze.org/LICENSE.txt")))))

(define-public python-guizero
  (package
    (name "python-guizero")
    (version "1.3.0")
    (source
     (origin
       (method git-fetch)
       (uri
        (git-reference
         (url "https://github.com/lawsie/guizero")
         (commit version)))
       (file-name (git-file-name name version))
       (sha256
        (base32 "0mf9gfc89cbxmvnfmxipyqdxirfirj42lkirz9qg347qjhln36by"))))
    (build-system python-build-system)
    (arguments
      ;; _XSERVTransmkdir: ERROR: euid != 0,directory /tmp/.X11-unix will not be created.
      '(#:tests? #f ; FIXME
        #:phases
        (modify-phases %standard-phases
          (add-before 'check 'pre-check
            (lambda _
              (system "Xvfb :1 &")
              (setenv "DISPLAY" ":1")))
          (replace 'check
            (lambda* (#:key tests? inputs outputs #:allow-other-keys)
              (when tests?
                (invoke "pytest" "-vv")))))))
    (native-inputs
      (list python-pytest xorg-server))
    (propagated-inputs
      `(("python-tkinter" ,python "tk")
        ("python-pillow" ,python-pillow)))
    (home-page "https://github.com/lawsie/guizero")
    (synopsis "Python module to allow learners to easily create GUIs")
    (description
"@code{python-guizero} is a Python 3 library for creating simple GUIs.
It is designed to allow new learners to quickly and easily create GUIs
for their programs.")
    (license license:bsd-3)))

(define-public onlykey-udev-rules
  (package
   (name "onlykey-udev-rules")
   (version "5.3.4")
   (source
    (origin
     (method git-fetch)
     (uri (git-reference
           (url "https://github.com/trustcrypto/OnlyKey-App")
           (commit (string-append "v" version))))
     (file-name (git-file-name name version))
     (sha256
      (base32 "19qjqiaqidl5bgpb3xiynm3scf3gfhdbbrkw484qffj8694l6gwy"))))
   (build-system copy-build-system)
   (arguments
    '(#:install-plan
      '(("./resources/linux/49-onlykey.rules" "etc/udev/rules.d/"))))
   (home-page "https://onlykey.io/")
   (synopsis "Onlykey UDEV rules")
   (description "UDEV rule in order for non-root users
to be able to communicate with USB devices")
   (license license:none)))

(define-public python-onlykey-solo-python
  (package
   (name "python-onlykey-solo-python")
   (version "0.0.28")
   (source
    (origin
     (method url-fetch)
     (uri (pypi-uri "onlykey-solo-python" version))
     (sha256
      (base32 "1xj1rzz6pqdsy0p2cr1vas3nw0l0ysxq6ww1hgiyb0cfim5bkf1i"))))
   (build-system python-build-system)
   (arguments '(#:tests? #f))          ;no tests
   (propagated-inputs
    (list python-click
          python-cryptography
          python-ecdsa
          python-fido2
          python-intelhex
          python-pyserial
          python-pyusb
          python-requests))
   (home-page "https://github.com/trustcrypto/onlykey-solo-python")
   (synopsis "Python library for OnlyKey with Solo FIDO2")
   (description "Python library for OnlyKey with Solo FIDO2")
   (license license:asl2.0)))

(define-public python-pyfzf
  (package
    (name "python-pyfzf")
    (version "0.2.2")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "pyfzf" version))
        (sha256
          (base32 "0hfmi91p6qyzgmq9zvp3is3zsz0mgsrcawcr5g5apmmksr7j6dca"))))
    (build-system python-build-system)
    (propagated-inputs (list python-plumbum))
    (home-page "https://github.com/nk412/pyfzf")
    (synopsis "Python wrapper for fzf")
    (description "Python wrapper for junegunn's fuzzyfinder @code{fzf}.")
    (license license:expat)))

(define-public python-gql
;; TODO: CLI currently broken
;;  λ gql-cli -h
;; Traceback (most recent call last):
;;   File "/gnu/store/fns32idy0j0fiwf4v1pl3zsqjmrnf14b-python-gql-3.0.0/bin/.gql-cli-real", line 6, in <module>
;;     from gql.cli import get_parser, main
;;   File "/gnu/store/fns32idy0j0fiwf4v1pl3zsqjmrnf14b-python-gql-3.0.0/lib/python3.9/site-packages/gql/__init__.py", line 11, in <module>
;;     from .client import Client
;;   File "/gnu/store/fns32idy0j0fiwf4v1pl3zsqjmrnf14b-python-gql-3.0.0/lib/python3.9/site-packages/gql/client.py", line 20, in <module>
;;     from .utilities import build_client_schema
;;   File "/gnu/store/fns32idy0j0fiwf4v1pl3zsqjmrnf14b-python-gql-3.0.0/lib/python3.9/site-packages/gql/utilities/__init__.py", line 1, in <module>
;;     from .build_client_schema import build_client_schema
;;   File "/gnu/store/fns32idy0j0fiwf4v1pl3zsqjmrnf14b-python-gql-3.0.0/lib/python3.9/site-packages/gql/utilities/build_client_schema.py", line 1, in <module>
;;     from graphql import GraphQLSchema, IntrospectionQuery
;; ImportError: cannot import name 'IntrospectionQuery' from 'graphql' (/gnu/store/4rbbgc5sik2r2l9532p79xb5b825hj6c-python-graphql-core-3.1.2/lib/python3.9/site-packages/graphql/__init__.py)
  (package
    (name "python-gql")
    (version "3.0.0")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "gql" version))
        (sha256
          (base32 "1cj7zlgl1fa60z9qrbs7fnwg5hkgvvknvk75ddwciblwls0gh7x2"))))
    (build-system python-build-system)
    (arguments
     '(#:tests? #f ; TODO
       #:phases
       ;; TODO
       ;; Reason for disabling sanity check
       ;; ...checking requirements: ERROR:
       ;; gql==3.0.0 ContextualVersionConflict(graphql-core 3.1.2
       ;; Requirement.parse('graphql-core<3.3,>=3.2'), {'gql'})
       (modify-phases %standard-phases
         (delete 'sanity-check))))  ; FIXME tests and sanity-check
    (native-inputs
      (list python-parse
            python-pytest
            python-pytest-asyncio
            python-pytest-cov
            python-mock
            python-vcrpy
            python-aiofiles))
    (propagated-inputs
      (list python-graphql-core ; install_requires
            python-yarl
            python-aiohttp ; install_aiohttp_requires

            python-requests ; install_requests_requires
            python-requests-toolbelt
            python-urllib3

            python-websockets ; install_websockets_requires

            python-botocore ; install_botocore_requires
            ))
    (home-page "https://github.com/graphql-python/gql")
    (synopsis "GraphQL client for Python")
    (description
"@code{python-gql} is a GraphQL client which plays nicely with
other graphql implementations compatible with the spec.  GQL supports
multiple transports to communicate with the backend such as Websockets,
HTTP, Absinthe, and more.")
    (license license:expat)))

(define-public python-types-urllib3
  (package
    (name "python-types-urllib3")
    (version "1.26.7")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "types-urllib3" version))
        (sha256
          (base32 "1lp3c9csw1ymaz1iq7b5f9s8nywamj5015422knhb9m99fzgplfg"))))
    (build-system python-build-system)
    (home-page "https://github.com/python/typeshed")
    (synopsis "Typing stubs for urllib3")
    (description "Typing stubs for urllib3")
    (license license:asl2.0)))

(define-public python-types-requests
  (package
    (name "python-types-requests")
    (version "2.27.7")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "types-requests" version))
        (sha256
          (base32 "0g5ip8jnq1k3ncsyxnfgc38d1siw5ybm7j8xn3jvrp4caa4d92zk"))))
    (build-system python-build-system)
    (propagated-inputs (list python-types-urllib3))
    (home-page "https://github.com/python/typeshed")
    (synopsis "Typing stubs for requests")
    (description "Typing stubs for requests")
    (license license:asl2.0)))

(define-public python-types-mock
  (package
    (name "python-types-mock")
    (version "4.0.8")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "types-mock" version))
        (sha256
          (base32 "03yys9jmv3vq468mwg159wkzshik5iw1bhihfh7pakhmr6r59p53"))))
    (build-system python-build-system)
    (home-page "https://github.com/python/typeshed")
    (synopsis "Typing stubs for mock")
    (description "Typing stubs for mock")
    (license license:asl2.0)))

(define-public python-types-aiofiles
  (package
    (name "python-types-aiofiles")
    (version "0.8.3")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "types-aiofiles" version))
        (sha256
          (base32 "1hh2zfg8vd2yid0d9aibd3raijqbhybmdqqw8hwixa08zgn5bi3p"))))
    (build-system python-build-system)
    (home-page "https://github.com/python/typeshed")
    (synopsis "Typing stubs for aiofiles")
    (description "Typing stubs for aiofiles")
    (license license:asl2.0)))

(define-public python-crlf
  (package
    (name "python-crlf")
    (version "cj8")
    (source
     (origin
       (method git-fetch)
       (uri
        (git-reference
         (url "https://github.com/pflanze/python-crlf")
         (commit version)))
       (file-name (git-file-name name version))
       (sha256
        (base32 "1hcp8n3ji7vxmjsj18nqy0dgp978vpdr8vxs1ah926x48iha04w3"))))
    (build-system python-build-system)
    (arguments
     '(#:phases
       (modify-phases %standard-phases
         (replace 'check
           (lambda* (#:key tests? inputs outputs #:allow-other-keys)
             (when tests?
               (invoke "python" "lineEnding.py")))))))
    (home-page "https://github.com/pflanze/python-crlf")
    (synopsis "Line ending detection library")
    (description "To prevent Python from decoding and canonicalizing line
endings and thus preventing detection, binary mode is used for opening, which
means that byte strings are read instead of normal strings.  Currently
@code{read} is used and a loop.  This doesn't hide the underlying workings and
is hence useful to explain the workings of, but nicer code could probably be
written using iterator based operations like @code{drop_while}.")
    (license license:expat)))

(define-public python-temppathlib
  (package
    (name "python-temppathlib")
    (version "1.1.0")
    (source (origin
              (method url-fetch)
              (uri (pypi-uri "temppathlib" version))
              (sha256
               (base32
                "07vx17pm80kpp465npwzs2al7vxa8gp926x1vpp9dqzycfn8n7xk"))))
    (build-system python-build-system)
    (native-inputs (list python-coverage
                         python-mypy
                         python-pydocstyle
                         python-pylint
                         python-tox
                         python-twine
                         python-yapf))
    (home-page "https://github.com/Parquery/temppathlib")
    (synopsis "Wrap tempfile to give you pathlib.Path.")
    (description "Wrap tempfile to give you pathlib.Path.")
    (license license:expat)))

(define-public python-setuptools-markdown
  (package
    (name "python-setuptools-markdown")
    (version "0.4.1")
    (source
     (origin
       (method url-fetch)
       (uri (pypi-uri "setuptools-markdown" version))
       (sha256
        (base32 "0a8c9yr07w86c3ipxw6pwim27fq2bh7lxlw6ysl8msrhly20gnp8"))))
    (build-system python-build-system)
    ;; there are no tests for this package
    (propagated-inputs
     (list
      python-pypandoc))
    (home-page "https://github.com/msabramo/setuptools-markdown")
    (synopsis "Use markdown for your project description")
    (description "Python-setuptools-markdown is a deprecated package that is
required by python-miditime.  Instead of using this, you should use the built-in
functionality of setuptools and PyPI.")
    (license license:expat)))

;; XXX: No longer builds because of the Python 2 removal upstream
(define-public python-miditime
  (package
    (name "python-miditime")
    (version "1.1.3")
    (source
     (origin
       (method url-fetch)
       (uri (pypi-uri "miditime" version))
       (sha256
        (base32 "0d18y6glcahhd4hyv6madnvj06j13qwhyy0r8z8kw050fypcr51c"))))
    (build-system python-build-system)
    (arguments
     '(#:tests? #f))                    ; tests are currently failing
    (propagated-inputs
     (list
      python-setuptools-markdown
      python-pytz))
    (home-page "https://github.com/cirlabs/miditime")
    (synopsis "Generate MIDI files from time series data")
    (description "Do you have time time series data you want to play as music?
Of course you do! MIDITime converts any kind of time series data into pitch,
velocity and duration values based on musical options that you set up, then
outputs a .mid file.")
    (license license:expat)))

(define-public python-recutils
  (let ((commit "8268b2591874a8e9034a4677ca10c380c88b25ab")
        (revision "0"))
    (package
      (name "python-recutils")
      (version commit)
      (source
       (origin
         (method git-fetch)
         (uri
          (git-reference
           (url "https://github.com/ttymck/python-recutils")
           (commit version)))
         (file-name (git-file-name name commit))
         (sha256
          (base32 "1hrr6lp4a35zp6y4whipalgh6k4gwwjwfm5y6kar6rsn0lc879df"))))
      (build-system python-build-system)
      (native-inputs
        (list python-pytest))
      (inputs
        (list python-click))
      (arguments
        '(#:phases
          (modify-phases %standard-phases
            (replace 'check
              (lambda* (#:key tests? inputs outputs #:allow-other-keys)
                (when tests?
                  ;; Why does this test fail?
                  (invoke "pytest" "-vv" "-k" "not test_parse_type")))))))
      (home-page "https://github.com/ttymck/python-recutils")
      (synopsis "GNU recutils implementation in python")
      (description
"@code{python-recutils} is a @code{recutils} implementation implemented
in python.")
      (license license:none))))

(define-public python-tinyrecord
  (package
    (name "python-tinyrecord")
    (version "0.2.0")
    (source
     (origin
       (method git-fetch)
       (uri (git-reference
              (url "https://github.com/eugene-eeo/tinyrecord")
              (commit (string-append "v" version))))
       (file-name (git-file-name "tinyrecord" version))
       (sha256
        (base32
         "12rmg0h7j7izhkj2465skmbbz5wkvhi9zlga1qwj9jldgfj22plq"))))
    (build-system python-build-system)
    (native-inputs
      (list python-pytest))
    (propagated-inputs
      (list python-tinydb))
    (arguments
      `(#:phases
        (modify-phases %standard-phases
          (replace 'check
            (lambda* (#:key tests? #:allow-other-keys)
              (when tests?
                (invoke "pytest" "-v" "tests.py")))))))
    (home-page "https://github.com/eugene-eeo/tinyrecord")
    (synopsis "Transaction support for TinyDB")
    (description
"@code{python-tinyrecord} is a library which implements atomic transaction
support for the TinyDB NoSQL database.  It uses a record-first then
execute architecture which allows us to minimize the time that we are
within a thread lock")
    (license license:expat)))

(define megadose-args
  `(#:tests? #f ; Tests require internet access.
    #:phases
    (modify-phases %standard-phases
      (add-after 'unpack 'remove-argparse-dependency
        (lambda* (#:key inputs outputs #:allow-other-keys)
        ;; https://github.com/megadose/holehe/pull/74
            (substitute* "setup.py"
              (("argparse") "")
              (("bs4") "")))))))

(define-public python-holehe
  (package
    (name "python-holehe")
    (version "1.60.3")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "holehe" version))
        (sha256
          (base32 "1wc77rlkdb1z97kw2k492lvzskw8rdc7kabz1cr86cz92bi68gcx"))))
    (build-system python-build-system)
    (arguments megadose-args)
    (propagated-inputs
      (list python-beautifulsoup4
            python-colorama
            python-httpx
            python-termcolor
            python-tqdm
            python-trio))
    (home-page "https://github.com/megadose/holehe")
    (synopsis "Efficiently finding registered accounts from emails")
    (description
"@code{python-holehe} checks if an email is attached to an account on
sites like twitter, instagram, imgur and more than 120 others.")
    (license license:gpl3+)))

(define-public python-ignorant
  (package
    (name "python-ignorant")
    (version "1.2")
    (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "ignorant" version))
        (sha256
          (base32 "1kfkrx3ryxvlhp7n5xcq8r65xr3is1s5hd71bxiy88rf9w7w9f28"))))
    (build-system python-build-system)
    (propagated-inputs
      (list
        python-beautifulsoup4
        python-httpx
        python-termcolor
        python-tqdm
        python-trio))
    (arguments megadose-args)
    (home-page "http://github.com/megadose/ignorant")
    (synopsis "Check if a phone number is used on different sites")
    (description
"@code{ignorant} allows you to check if a phone is used on different sites
like snapchat.")
    (license license:gpl3+)))

